#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include "axistag.h"
#include "serialportdialog.h"
#include "console.h"
#include "serialportcommunication.h"
#include "serialportmasterthread.h"
#include "temperatureplotsettingsdialog.h"

//#define STM32

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_xAxisRange(100.0),
    m_nPlot(0),
    m_plotPeriod(50),
    m_demoChecked(false)
{
    ui->setupUi(this);

    initTemperaturePlot();

    m_stringTemperatureData = new QString[TEMPERATURE_PORT_NUM];
    m_temperatureData = new double[TEMPERATURE_PORT_NUM];
    m_temperatureData[0] = 25.0;
//    memset(m_stringTemperatureData, 0, sizeof(QString) * TEMPERATURE_PORT_NUM);
//    memset(m_temperatureData, 0, sizeof(double) * TEMPERATURE_PORT_NUM);

    m_console = new Console(this);
    m_console->setEnabled(false);
//    setCentralWidget(m_console);
    ui->consoleHorizontalLayout->addWidget(m_console);

    m_communication = new SerialPortCommunication(this);
    ui->CommunicationVerticalLayout->addWidget(m_communication);


    ui->mainSplitter->setStretchFactor(0, 7);
//    ui->mainSplitter->setStretchFactor(1, 1);
    ui->portSplitter->setStretchFactor(0, 6);
//    ui->portSplitter->setStretchFactor(1, 2);

    m_serialport = new QSerialPort(this);
    m_communication->setSerialPortInstance(m_serialport);

    m_serialportSettingsDlg = new SerialPortDialog(this);
    m_temperaturePlotSettingsDlg = new TemperaturePlotSettingsDialog(this);

    ui->actionConnect->setEnabled(true);
    ui->actionDisconnect->setEnabled(false);
    ui->actionQuit->setEnabled(true);
    ui->actionSerialPortConfigure->setEnabled(true);

    m_serialportStatus = new QLabel;
    ui->statusBar->addWidget(m_serialportStatus);
    m_temperatureRefreshStatus = new QLabel;
    ui->statusBar->addWidget(m_temperatureRefreshStatus);

    initActionsConnections();

    connect(m_serialport, SIGNAL(error(QSerialPort::SerialPortError)),
            this, SLOT(slotHandleError(QSerialPort::SerialPortError)));//connect(serial, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error), this, &MainWindow::handleError);
    connect(m_serialport, SIGNAL(readyRead()),
            this, SLOT(slotReadData()));//connect(serial, &QSerialPort::readyRead, this, &MainWindow::readData);

    connect(m_console, SIGNAL(signalGetData(QByteArray)),
            this, SLOT(slotWriteData(const QByteArray)));//connect(m_console, &Console::getData, this, &MainWindow::writeData);
    connect(m_serialportSettingsDlg, SIGNAL(signalApply()),
            this, SLOT(slotCopySerialPortSettings()));

    connect(m_communication, SIGNAL(signalSerialPortConnected()),
            this, SLOT(slotSerialPortConnected()));

    connect(m_temperaturePlotSettingsDlg, SIGNAL(signalUpdatePlotSettings(int)),
            this, SLOT(slotUpdatePlotSettings(int)));

    m_dataTimer.start(m_plotPeriod);//50
}

MainWindow::~MainWindow()
{
    delete ui;
    delete m_serialportSettingsDlg;
    delete m_serialport;
    delete m_console;
    delete m_communication;
    delete m_temperaturePlotSettingsDlg;
    delete[] m_stringTemperatureData;
    delete[] m_temperatureData;
}

void MainWindow::initActionsConnections()
{
    connect(ui->actionConnect, SIGNAL(triggered(bool)), this, SLOT(slotOpenSerialPort()));//connect(ui->actionConnect, &QAction::triggered, this, &MainWindow::openSerialPort);
    connect(ui->actionDisconnect, SIGNAL(triggered(bool)), this, SLOT(slotCloseSerialPort()));//connect(ui->actionDisconnect, &QAction::triggered, this, &MainWindow::closeSerialPort);
    connect(ui->actionSerialPortConfigure, SIGNAL(triggered(bool)), m_serialportSettingsDlg, SLOT(show()));//connect(ui->actionSerialPortConfigure, &QAction::triggered, settings, &MainWindow::show);
    connect(ui->actionClear, SIGNAL(triggered(bool)), m_console, SLOT(clear()));//connect(ui->actionClear, &QAction::triggered, console, &Console::clear);
    connect(ui->actionQuit, SIGNAL(triggered(bool)), this, SLOT(close()));//connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::close);

    connect(ui->actionPlotConfigure, SIGNAL(triggered(bool)), m_temperaturePlotSettingsDlg, SLOT(show()));
}

 void MainWindow::showStatusMessage(const QString &message)
 {
    m_serialportStatus->setText(message);
 }

 void MainWindow::initTemperaturePlot()
 {
     m_graph.clear();
     m_tag.clear();

     m_customPlot = new QCustomPlot(this);
//     setCentralWidget(m_customPlot);
     ui->plotHorizontalLayout->addWidget(m_customPlot);


     m_customPlot->yAxis->setTickLabels(false);
     //左轴仅镜像右内轴
     connect(m_customPlot->yAxis2, SIGNAL(rangeChanged(QCPRange)), m_customPlot->yAxis, SLOT(setRange(QCPRange)));

     m_customPlot->yAxis2->setVisible(true);
 //    m_customPlot->axisRect()->addAxis(QCPAxis::atRight);
     //设置时间轴
     QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
     timeTicker->setTimeFormat("%h:%m:%s");
     m_customPlot->xAxis->setTicker(timeTicker);

     qsrand(GRAPH_PLOT);
     for (int i = 0; i < GRAPH_PLOT; i++)
     {
         if (i < (GRAPH_PLOT - 1))
         {
             m_customPlot->axisRect()->addAxis(QCPAxis::atRight);
         }
         m_customPlot->axisRect()->axis(QCPAxis::atRight, i)->setPadding(30);
         QPointer<QCPGraph> graph = m_customPlot->addGraph(m_customPlot->xAxis, m_customPlot->axisRect()->axis(QCPAxis::atRight, i));
         int n = qrand() % 8;
         if (n < 2)
             n = 2;
         if (n > 8)
             n = 8;
         qDebug() << "rand = " << n;
         graph->setPen(QPen(QColor((n - 1) * 30, 50, (n + 2) * 30)));
         m_graph.push_back(graph);

         AxisTag *tag = new AxisTag(graph->valueAxis());
         tag->setPen(graph->pen());
         m_tag.push_back(tag);
     }

     connect(&m_dataTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
}

void MainWindow::updataTemperature(const QByteArray &temperatureData)
{
    m_stringTemperatureData[0] = QString(temperatureData);
//    qDebug() << "MainWindow: Temperature &0~5 = " << QString(temperatureData);
    qDebug() << "MainWindow: Temperature #0~5 = " << m_stringTemperatureData[0];
    if (m_stringTemperatureData[0].size() < TEMPERATURE_DATA_MAXSIZE)
    {
        std::string temperature = m_stringTemperatureData[0].toStdString();
        int indexT0 = temperature.find("t0");
        if (indexT0 > 0)
        {
            QString stringT0;

#ifdef STM32
            stringT0 = m_stringTemperatureData[0].mid(indexT0 + 5, 7);
#else
            stringT0 = m_stringTemperatureData[0].right(indexT0 + 2);
#endif

            qDebug() << "MainWindow: Temperature string #0 : " << stringT0;
            if (stringT0.size() > TEMPERATURE_DATA_MINSIZE)
            {
                double t0 = stringT0.toDouble();
                qDebug() << "MainWindow: Temperature double #0 : " << t0;
                if (abs(t0) > 0.1)
                {
                    m_temperatureData[0] = t0;
                }
            }
        }
    }
}

void MainWindow::slotOpenSerialPort()
{
    SerialPortDialog::SerialPortSettings p = m_serialportSettingsDlg->settings();

    m_serialport->setPortName(p.name);
    m_serialport->setBaudRate(p.baudRate);
    m_serialport->setDataBits(p.dataBits);
    m_serialport->setParity(p.parity);
    m_serialport->setStopBits(p.stopBits);
    m_serialport->setFlowControl(p.flowControl);

    if (m_serialport->open(QIODevice::ReadWrite))
    {
        m_console->setEnabled(true);
        m_console->setLocalEchoEnabled(p.localEchoEnabled);
        ui->actionConnect->setEnabled(false);
        ui->actionDisconnect->setEnabled(true);
        ui->actionSerialPortConfigure->setEnabled(false);
        showStatusMessage(tr("Connected to %1 : %2, %3, %4, %5, %6")
                          .arg(p.name).arg(p.stringBaudRate).arg(p.stringDataBits)
                          .arg(p.stringParity).arg(p.stringStopBits).arg(p.stringFlowControl));
        QPalette p = palette();
        p.setColor(QPalette::Base, Qt::black);
        p.setColor(QPalette::Text, Qt::green);
        m_console->setPalette(p);
    }
    else
    {
        QMessageBox::critical(this, tr("Error"), m_serialport->errorString());

        showStatusMessage(tr("Open error"));
    }
}

void MainWindow::slotCloseSerialPort()
{
    if (m_serialport->isOpen())
    {
        m_serialport->close();
        QPalette p = palette();
        p.setColor(QPalette::Base, QColor(240, 240, 240));
        p.setColor(QPalette::Text, Qt::green);
        m_console->setPalette(p);
    }
    m_console->setEnabled(false);
    ui->actionConnect->setEnabled(true);
    ui->actionDisconnect->setEnabled(false);
    ui->actionSerialPortConfigure->setEnabled(true);
    showStatusMessage(tr("Disconnected"));
}

void MainWindow::slotAbout()
{

}

void MainWindow::slotWriteData(const QByteArray &data)
{
    m_serialport->write(data);
}

void MainWindow::slotReadData()
{
    QByteArray data = m_serialport->readAll();
    m_console->putData(data);   
    updataTemperature(data);
}

void MainWindow::slotHandleError(QSerialPort::SerialPortError error)
{
    if (error == QSerialPort::ResourceError)
    {
        QMessageBox::critical(this, tr("Critical Error"), m_serialport->errorString());
        slotCloseSerialPort();
    }
}

void MainWindow::slotTimeout()
{
    int i = 0;
    double param[] = {0.3845, 0.4364, 0.6743};
    static QTime time(QTime::currentTime());
    double key = time.elapsed() / 1000.0;
    static double lastPointKey = 0;
    int dataPoint = 0;

    QVector<QPointer<QCPGraph>>::iterator it = m_graph.begin();

//    QPointer<QCPGraph> graph0 = (QPointer<QCPGraph>)(*it);
//    graph0->addData(key, 270.1);
//    m_customPlot->xAxis->rescale();
//    graph0->rescaleValueAxis(false, true);
//    double graphValue0 = graph0->dataMainValue(graph0->dataCount() - 1);
//    m_tag[0]->updatePosition(graphValue0);
//    m_tag[0]->setText(QString::number(graphValue0, 'f', 2));
//    dataPoint += graph0->data()->size();
//    it++;

    for (; it != m_graph.end(); it++)
    {
        QPointer<QCPGraph> graph = (QPointer<QCPGraph>)(*it);

        if (i == 0)
        {
//            m_mutex.lock();
//            graph->addData(graph->dataCount(), m_temperatureData[0]);
            graph->addData(key, m_temperatureData[0]);
//            graph->addData(key, 270.15);
//            m_mutex.unlock();
        }
        else
        {
            if (!m_demoChecked)
            {
                break;
            }
            graph->addData(key, qSin(graph->dataCount() / 50.0) + qSin(graph->dataCount() / 50.0 / param[i]) * 0.25 - 273.15);//graph->addData(graph->dataCount(), qSin(graph->dataCount() / 50.0) + qSin(graph->dataCount() / 50.0 / param[i]) * 0.25 - 273.15);
        }

        lastPointKey = key;
        //使用数据进行关键轴范围滚动
        m_customPlot->xAxis->rescale();
        graph->rescaleValueAxis(false, true);
//        m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().upper, 100, Qt::AlignRight);
        m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().upper, m_xAxisRange, Qt::AlignRight);
        //更新垂直轴标记位置和文本以匹配图形的最右侧数据点：
        double graphValue = graph->dataMainValue(graph->dataCount() - 1);
//        double graph2Value = mGraph2->dataMainValue(mGraph2->dataCount()-1);
        m_tag[i]->updatePosition(graphValue);
//        m_tag[1]->updatePosition(graph2Value);
        m_tag[i]->setText(QString::number(graphValue, 'f', 2));
//        m_tag[2]->setText(QString::number(graph2Value, 'f', 2));
        dataPoint += graph->data()->size();
        i++;
    }
    // calculate frames per second:
    static double lastFpsKey;
    static int frameCount;
    ++frameCount;
    if (key - lastFpsKey > 2) // average fps over 2 seconds
    {
      m_temperatureRefreshStatus->setText(
            QString("%1 FPS, Total Data points: %2")
            .arg(frameCount/(key - lastFpsKey), 0, 'f', 0)
            .arg(dataPoint));
      lastFpsKey = key;
      frameCount = 0;
    }
    //设置x轴范围
//    m_customPlot->xAxis->setRange(key, 32, Qt::AlignRight);
    m_customPlot->replot();
}

void MainWindow::slotCopySerialPortSettings()
{
    m_communication->getSerialPortSettings(m_serialportSettingsDlg->settings());
}

void MainWindow::slotSerialPortConnected()
{
    ui->actionConnect->setEnabled(false);
    ui->actionDisconnect->setEnabled(true);
}

void MainWindow::slotUpdatePlotSettings(int id)
{
    TemperaturePlotSettingsDialog::PlotSettings p = m_temperaturePlotSettingsDlg->settings();
    if (id == 0)
    {
        m_xAxisRange = p.xAxisRange;
        m_plotPeriod = p.plotPeriod;
        m_demoChecked = p.demoChecked;
        m_dataTimer.setInterval(m_plotPeriod);
        m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().upper, m_xAxisRange, Qt::AlignRight);
    }
    if (id == 1)
    {

    }
}
